#include"myshell.h"

char* gargv[args];
int gargc;
char pwd[1024];
int lastcode = 0;

#define NONE_REDIR 0
#define OUTPUT_REDIR 1
#define APPEND_REDIR 2
#define INPUT_REDIR 3

std::string filename;
int redir_type = NONE_REDIR;


//感觉下面的三个个获取提示符组成部分的函数可以用一个函数模板完成
static std::string GetUsr()
{
	std::string ret = getenv("USER");
	return ret.empty()? "None" : ret; 
}

static std::string GetHostName()
{
	
	std::string ret = getenv("LOGNAME");
	return ret.empty()? "None" : ret; 
}

static std::string GetPwd()
{
//光是这样获取pwd一直都是在子进程的路径下，这样我们就算cd ..了也无法改变pwd，因为这个操作是在父进程的路径下的	
//	std::string ret = getenv("PWD");
//	return ret.empty()? "None" : ret; 
	
	char temp[1024];
	//如果要实现命令提示符随着我们的cd操作实时变化的话
	//需要用系统调用函数getcwd
	getcwd(temp,sizeof(temp));

	//函数解释：往sizeof(wpd)大小的数组中写入“”中的信息
	snprintf(pwd,sizeof(pwd),"PWD=%s",temp);

	//将系统环境变量中的pwd覆盖成为我们所写入的信息
	putenv(pwd);
	
	std::string pwd_lable = temp;

	const std::string pwd_sep = "/";
	auto pos = pwd_lable.rfind(pwd_sep);
	
	if(pos == std::string::npos)
		return "None";
	
	pwd_lable = pwd_lable.substr(pos+pwd_sep.size());
	return pwd_lable.empty()? "None" : pwd_lable;
}

static std::string GetHomePath()
{
	std::string ret = getenv("HOME");
	return ret.empty()? "/" : ret;
}

void PrintCommandPrompt()
{
	printf("[%s@%s %s]#",GetUsr().c_str(),GetHostName().c_str(),GetPwd().c_str());
}

bool GetCommandString(char cmd_str_buff[] ,int len)
{
	if(cmd_str_buff == NULL || len<=0)
		return false;
	char *ret = fgets(cmd_str_buff ,len ,stdin);
	if(ret == NULL)
		return false;
	cmd_str_buff[strlen(cmd_str_buff)-1] = 0;
	return strlen(cmd_str_buff)==0 ? false : true ;
}

//宏定义函数
#define TrimSpace(start) do{\
	while(isspace(*start))\
	{\
		start++;\
	}\
	}while(0)
	


void CheckRedir(char cmd[])
{
	char *start = cmd;
	char *end = &cmd[strlen(cmd)-1];
	while(start<end)
	{
		if(*start == '>')
		{
			if(*(start +1) == '>')
			{
				//追加重定向 >>
				redir_type = APPEND_REDIR;
				*start = '\0';
				start += 2;
				TrimSpace(start);
				filename = start;
				break;

			}
			else
			{
				//输出重定向 >
				redir_type = OUTPUT_REDIR;
				*start = '\0';
				start++;
				TrimSpace(start);
				filename = start;
				break;

			}
		}
		else if(*start == '<')
		{
			//输入重定向 <
			redir_type = INPUT_REDIR;
			*start = '\0';
			start++;
			TrimSpace(start);//移除空格
			filename = start;
			break;
		}
		else
		{
			start++;
		}
	}
}


bool ParceCommand(char cmd[])
{
	if(cmd == NULL)
		return false;
	gargv[gargc++] = strtok(cmd," ");
	while((bool)(gargv[gargc++] = strtok(NULL," ")));
	gargc--;

//#define DEBUG
#ifdef DEBUG
	
	printf("gargc:%d\n",gargc);\

	printf("-----------------\n");
	
	for(int i=0 ; gargv[i];i++)
	{
		printf("gargv[%d]:%s\n",i,gargv[i]);
	}

#endif

	return true;
}


void init()
{
	gargc = 0;
	memset(gargv,0,sizeof(gargv));
	filename.clear(); 
	redir_type = NONE_REDIR;
}

bool BuiltInCommand()
{
	std::string cmd = gargv[0];
	bool ret = false;
	if(cmd == "cd")
	{
		if(gargc == 2)
		{
			ret = true;
			if(gargv[1] == "~")
				chdir(GetHomePath().c_str());
		
			else
			{
				chdir(gargv[1]);
			}
		}
		else if(gargc == 1)
		{
			chdir(GetHomePath().c_str());
			ret = true;
		}
		else
		{
			//输入错误了
			std::cout<<"输入错误，请重新输入！"<<std::endl;
		}
	}
	else if(cmd == "echo")
	{
		if(gargc == 2)
		{
			ret = true;
			std::string args = gargv[1]; 
			if(args[0] == '$')
			{
				if(args[1] == '?')
					printf("lastcode:%d\n",lastcode);
				else
				{
					const char* name = &args[1];
					printf("%s\n",getenv(name));
					lastcode = 0;
				}
			}
		}
	}

	return ret;
}

void ForkAndExec()
{
	pid_t id = fork();
	if(id<0)
		perror("fork");
	else if(id == 0)
	{
		//子进程
		if(redir_type == OUTPUT_REDIR)
		{
			//输出重定向
			int output = open(filename.c_str() ,O_CREAT | O_WRONLY | O_TRUNC ,0666);
			dup2(output ,1);	
		}
		else if(redir_type == APPEND_REDIR)
		{
			//追加重定向
			int appendfd = open(filename.c_str() ,O_CREAT | O_WRONLY | O_APPEND ,0666);
			dup2(appendfd ,1);
		}
		else if(redir_type == INPUT_REDIR)
		{
			//输入重定向
			int input = open(filename.c_str() ,O_RDONLY);
			dup2(input ,0);
		}
		else
		{
			//--Do nothing--
		}
		execvp(gargv[0],gargv);
		perror("execvp");
		exit(0);
	}
	else
	{
		//父进程
		int status;
		pid_t rid = waitpid(id ,&status ,0);
		if(rid < 0)
			perror("waitpid");
		else if(id > 0)
		{
			lastcode = WEXITSTATUS(status);
		}
	}
}

